#ifndef XENENGINE_XEN_PHYSICAL_BODY_HPP
#define XENENGINE_XEN_PHYSICAL_BODY_HPP

#include "xen/pch.hpp"
#include "xen/core.hpp"
#include "pch.hpp"
#include "mass.hpp"
#include "world.hpp"
#include "geom.hpp"

namespace Xen {

    namespace Physical {

        class Body {
        public:

            Body(const World& world);
            Body(const World& world, const glm::vec3& pos, const glm::vec3& rotation);
            virtual ~Body();

            void SetPosition(const glm::vec3& pos);
            void SetRotation(const glm::vec3& rotation);
            const glm::vec3 GetPosition();
            const glm::vec3 GetRotation();

            virtual const Mass& GetMass() const = 0;

            bool operator==(const Body& b)const {
                return IsSameAs(b);
            }

            bool operator!=(const Body& b) const {
                return !IsSameAs(b);
            }

            inline bool IsSameAs(const Body& body) const {
                return id_ == body.id_;
            }

            void AttachGeom(const Ref<Geomentry>& g);

            void SetLinearVel(const glm::vec3& vel);
            void SetAngularVel(const glm::vec3& vel);
            glm::vec3 GetLinearVel() const;
            glm::vec3 GetAngularVel() const;
            void SetForce(const glm::vec3& f);
            glm::vec3 GetForce() const;
            void SetTorque(const glm::vec3& f);
            glm::vec3 GetTorque() const;


        protected:
            dBodyID id_;

        private:
            glm::vec3 position_ = {0, 0, 0};
            glm::vec3 rotation_ = {0, 0, 0};
        };

        class SphereBody: public Body {
        public:
            SphereBody(const World& world, float mass, const glm::vec3& position, float r);

            const Mass& GetMass() const override;
            float GetRadius() const { return r_; }

        private:
            SphereMass mass_;
            float r_;
        };

        class BoxBody: public Body {
        public:
            BoxBody(const World &world, float mass, const glm::vec3 &position, const glm::vec3& l);

            const Mass &GetMass() const override;
            const glm::vec3& GetL() const { return l_; }

        private:
            glm::vec3 l_;
            BoxMass mass_;
        };
    }

}

#endif
